#!/bin/bash
# Compiles an LLVM bitcode file to HSAIL or GCN ISA

# enable bash debugging
KMDBSCRIPT="${KMDBSCRIPT:=0}"

# dump the LLVM bitcode
KMDUMPLLVM="${KMDUMPLLVM:=0}"

# dump the brig
KMDUMPBRIG="${KMDUMPBRIG:=0}"

# dump the isa
KMDUMPISA="${KMDUMPISA:=0}"

# pass extra options to OPT
# KMOPTOPT can be used to pass last-minute options to opt in the backend
# if not set, then "-O3" would be passed to opt
KMOPTOPT="${KMOPTOPT:="-O3"}"

# pass extra options to LLC
# KMOPTLLC can be used to pass last-minute options to llc in the backend
# if not set, then "-O2" will be passed to llc
KMOPTLLC="${KMOPTLLC:="-O2"}"

if [ $KMDBSCRIPT == "1" ]; then
  set -x
fi

# check command line argument
if [ "$#" -lt 1 ]; then
  echo "Usage: $0 input_LLVM_IR (--amdgpu-target=(GPU family name))" >&2
  echo "  --amdgpu-target=(fiji | kaveri | carrizo | hawaii | tonga)" >&2
  echo "           selects AMDGPU target" >&2
  exit 1
fi

if [ ! -f $1 ]; then
  echo "input LLVM IR $1 is not valid" >&2
  exit 1
fi

BINDIR=$(dirname $0)
HLC_LLVM_LINK=$BINDIR/../../hlc/bin/llvm-link
HLC_OPT=$BINDIR/../../hlc/bin/opt
HLC_LLC=$BINDIR/../../hlc/bin/llc
HLC_ASM=$BINDIR/../../HSAILasm/HSAILasm
NEWLIB=$BINDIR/../../lib



HSA_LLVM_BIN_DIR="${BASH_SOURCE%/*}/../../llvm/bin"
if [ -d "$HSA_LLVM_BIN_DIR" ]; then
    HLC_LLVM_LINK=$HSA_LLVM_BIN_DIR/llvm-link
    HLC_OPT=$HSA_LLVM_BIN_DIR/opt
    HLC_LLC=$HSA_LLVM_BIN_DIR/llc
fi

HSA_USE_AMDGPU_BACKEND=@HSA_USE_AMDGPU_BACKEND@

if [ $HSA_USE_AMDGPU_BACKEND == "ON" ]; then
  LLD=$HSA_LLVM_BIN_DIR/ld.lld
  KM_USE_AMDGPU="${KM_USE_AMDGPU:=1}"
fi

if [ $KMDUMPLLVM == "1" ]; then
  cp $1 ./dump.fe.bc
fi

if [ $KM_USE_AMDGPU ]; then
  HCC_EXTRA_LIBRARIES="$HCC_EXTRA_LIBRARIES $NEWLIB/hsail-amdgpu-wrapper.ll"
fi

$HLC_LLVM_LINK -suppress-warnings -o $1.linked.bc $1 $NEWLIB/builtins-hsail.opt.bc $HCC_EXTRA_LIBRARIES

# error handling for HSAIL llvm-link
RETVAL=$?
if [ $RETVAL != 0 ]; then
  exit $RETVAL
fi

if [ $KMDUMPLLVM == "1" ]; then
  cp $1.linked.bc ./dump.linked.bc
fi

################
# AMDGPU target 
################

AMDGPU_TARGET=@AMDGPU_TARGET@

ARGS="$@"
for ARG in $ARGS
do
  ######################
  # Parse AMDGPU target
  ######################
  case $ARG in
    --amdgpu-target=*)
    AMDGPU_TARGET="${ARG#*=}"
    continue
    ;;
  esac
done

# Optimization notes:
#  -disable-simplify-libcalls:  prevents transforming loops into library calls such as memset, memcopy on GPU 

if [ $KM_USE_AMDGPU ]; then
  $HLC_OPT $KMOPTOPT -mtriple amdgcn--amdhsa -mcpu=$AMDGPU_TARGET -disable-simplify-libcalls -verify $1.linked.bc -o $1.opt.bc
else
  $HLC_OPT $KMOPTOPT -disable-simplify-libcalls -verify $1.linked.bc -o $1.opt.bc
fi

# error handling for HSAIL opt
RETVAL=$?
if [ $RETVAL != 0 ]; then
  exit $RETVAL
fi

if [ $KMDUMPLLVM == "1" ]; then
  cp $1.opt.bc ./dump.opt.bc
fi

if [ $KM_USE_AMDGPU  ]; then
  $HLC_LLC $KMOPTLLC -mtriple amdgcn--amdhsa -mcpu=$AMDGPU_TARGET -filetype=obj -o $1.hsail $1.opt.bc
  if [ $KMDUMPISA == "1" ]; then
    $HLC_LLC $KMOPTLLC -mtriple amdgcn--amdhsa -mcpu=$AMDGPU_TARGET -filetype=asm -o $1.isa $1.opt.bc
    mv $1.isa ./dump.isa
  fi
else
  $HLC_LLC $KMOPTLLC -march=hsail64 -filetype=asm -o $1.hsail $1.opt.bc
fi

# error handling for HSAIL llc
RETVAL=$?
if [ $RETVAL != 0 ]; then
  exit $RETVAL
fi

if [ $KMDUMPBRIG == "1" ]; then
    cp $1.hsail ./dump.hsail
fi

if [ $KM_USE_AMDGPU ]; then
  $LLD  -shared $1.hsail -o $1.brig
else
  cat $NEWLIB/hsa_builtins.hsail >> $1.hsail
  $HLC_ASM -assemble -o $1.brig $1.hsail
fi

# error handling for HSAILasm
RETVAL=$?
if [ $RETVAL != 0 ]; then
  exit $RETVAL
fi

if [ $KMDUMPBRIG == "1" ]; then
    cp $1.brig ./dump.hsa_builtins.brig
fi
